#ifndef SV_HPP
#define SV_HPP 

/*************************************WRITE BY LJX*****************************************/

#include <vector>
#include <thread>
#include <deque>
#include <mutex>
#include <functional>
#include <condition_variable>

#ifndef slots
#define slots
#endif

#ifndef signals
#define signals        public
#endif

#ifndef emit
#define emit
#endif

/// 命名空间 Sv
#ifndef SV_NAMESPACE
#define SV_NAMESPACE Sv
#endif

namespace SV_NAMESPACE{

enum Connected{ DirectConnection,QueuedConnection };

template<unsigned int Size> struct SvImp;
template<> struct SvImp<0>{
    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),receiver)});
    }

    /// 支持匿名函数
    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot))});
    }

    /// 支持全局函数
    template<typename Sender,typename Signal,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(slot)});
    }
};

#define GENERATOR(size,...)\
    template<> struct SvImp<size>{\
        template<typename Sender,typename Signal,typename Receiver,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),receiver,__VA_ARGS__)});\
        }\
        template<typename Sender,typename Signal,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),__VA_ARGS__)});\
        }\
        template<typename Sender,typename Signal,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(slot,__VA_ARGS__)});\
        }\
    };
GENERATOR(1,_1)
GENERATOR(2,_1,_2)
GENERATOR(3,_1,_2,_3)
GENERATOR(4,_1,_2,_3,_4)
GENERATOR(5,_1,_2,_3,_4,_5)
GENERATOR(6,_1,_2,_3,_4,_5,_6)
GENERATOR(7,_1,_2,_3,_4,_5,_6,_7)
GENERATOR(8,_1,_2,_3,_4,_5,_6,_7,_8)
GENERATOR(9,_1,_2,_3,_4,_5,_6,_7,_8,_9)
GENERATOR(10,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10)
GENERATOR(11,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11)
GENERATOR(12,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12)
GENERATOR(13,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13)
GENERATOR(14,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14)
GENERATOR(15,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15)
GENERATOR(16,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_14,_16)
GENERATOR(17,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17)
GENERATOR(18,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18)
GENERATOR(19,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19)
GENERATOR(20,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20)
GENERATOR(21,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21)
GENERATOR(22,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22)
GENERATOR(23,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23)
GENERATOR(24,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24)
GENERATOR(25,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25)
GENERATOR(26,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26)
GENERATOR(27,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27)
GENERATOR(28,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28)
GENERATOR(29,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29)
#undef GENERATOR

template<typename Sender,typename Signal,typename Receiver,typename Slot>
inline void connect(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),receiver,std::forward<Slot>(slot),t);
}

/// 支持匿名函数
template<typename Sender,typename Signal,typename Slot>
inline void connect(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),std::forward<Slot>(slot),t);
}

/// 支持全局函数
template<typename Sender,typename Signal,typename Slot>
inline void connect(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),slot,t);
}

template<typename Sender,typename Signal>
inline void disconnect(Sender* sender,Signal signal)
{
    (sender->*signal).clear();
}

}

class SvQueue
{
    using Tp     = std::function<void()>;
    using Locker = std::unique_lock<std::mutex>;

    bool                                flag;
    bool                                terminal;
    std::mutex                          mutex;
    std::condition_variable             cv;
    std::thread                         thread;
    std::deque<Tp>                      queue;
public:
    static SvQueue& instance()
    {
        static SvQueue svQueue;
        return svQueue;
    }

    static void exec()
    {
        SvQueue::instance().wait();
    }

public:
    void enqueue(Tp tp)
    {
        Locker locker(mutex);
        queue.push_back(tp);
        cv.notify_one();
    }

    Tp dequeue()
    {
        Locker locker(mutex);
        Tp tp = queue.front();
        queue.pop_front();
        return tp;
    }

protected:
    SvQueue()
    {
        flag = true;
        terminal = true;
        thread = std::thread(&SvQueue::run,this);
    }

    ~SvQueue()
    {
        wait();
    }

protected:
    void wait()
    {
        flag = false;
        cv.notify_one();
        if(thread.joinable()){
            thread.join();
        }
    }

    void terminate()
    {
        terminal = false;
        wait();
    }

protected:
    void run()
    {
        while (terminal)
        {
            {
                Locker locker(mutex);
                cv.wait(locker, [this]{ return !queue.empty() || !flag; });
                if(queue.size() == 0){
                    if(flag == false){
                        break;
                    }else{
                        continue;
                    }
                }
            }

            Tp tp = dequeue();
            tp();
        }
    }
};

template<typename... Args>
class sv : protected std::vector<std::pair<char,std::function<void(Args...)>>>
{
    using Tp                                = std::pair<char,std::function<void(Args...)>>;
    using Base                              = std::vector<Tp>;
    static constexpr unsigned int Parmers   = sizeof...(Args);

    template<unsigned int Size> friend struct SV_NAMESPACE::SvImp;

    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Receiver* receiver,Slot slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Slot&& slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Slot* slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal>
    friend void SV_NAMESPACE::disconnect(Sender* sender,Signal signal);

    using Locker = std::unique_lock<std::mutex>;
    std::mutex                          mutex;
public:
    template<typename... Params>
    inline void operator()(Params&&... parmers)
    {
        Locker   locker(mutex);
        typename Base::const_iterator it  = this->begin();
        typename Base::const_iterator end = this->end();
        while(it != end){
            switch (it->first)
            {
            case SV_NAMESPACE::DirectConnection:
                it->second(std::forward<Params>(parmers)...);
                break;
            case SV_NAMESPACE::QueuedConnection:
                SvQueue::instance().enqueue([=](){ it->second(parmers...); });
                break;
            }
            ++it;
        }
    }

protected:
    sv& operator=(sv&&)         = delete;
    sv& operator=(const sv&)    = delete;

protected:
    void clear()
    {
        Locker locker(mutex);
        Base::clear();
    }

    void push_back(const Tp& tp)
    {
        Locker locker(mutex);
        Base::push_back(tp);
    }

    void push_back(Tp&& tp)
    {
        Locker locker(mutex);
        Base::push_back(tp);
    }
};

#endif // SV_HPP
